

#include <cegame/cegeometryloader.h>

ceGeometryLoader* ceGeometryLoader::static_instance = 0;

ceGeometryLoader::ceGeometryLoader ()
	: device (device)
{
}

void ceGeometryLoader::Initialize (LPDIRECT3DDEVICE9 device)
{
	this->device = device;
}


iGeometry* ceGeometryLoader::Load (iFile* file)
{
	ceXmlDocument doc;
	if (!doc.Open(file))
	{
		return 0;
	}

	ceXmlElement elem = doc.GetRootElement();
	if (elem.GetTagName () == "rendermesh")
	{
		return LoadRenderMesh (elem);
	}

	return 0;
}

ceRenderMesh* ceGeometryLoader::LoadRenderMesh (iFile* file)
{
	ceXmlDocument doc;
	if (!doc.Open(file))
	{
		return 0;
	}

	return LoadRenderMesh (doc.GetRootElement());
}


ceRenderMesh* ceGeometryLoader::LoadRenderMesh (ceXmlElement elem)
{
	if (elem.GetTagName () != "rendermesh")
	{
		return 0;
	}

	struct Vertex
	{
		float x, y, z;
		float nx, ny, nz;
		float tu, tv;
	};

	ceXmlElement verticesElem = elem.GetChild ("vertices");
	ceXmlElement indicesElem = elem.GetChild ("indices");

	unsigned numVertices = verticesElem.GetIntAttribute ("num");
	unsigned numTrigons = indicesElem.GetIntAttribute ("num");
	unsigned numIndices = numTrigons*3;

	Vertex* vertices = new Vertex [numVertices];
	unsigned short* indices = new unsigned short[numIndices];

	for (unsigned i=0; i<numVertices; i++)
	{
		ceXmlElement vertexElem = verticesElem.GetChild (i, "v");
		vertices [i].x = vertexElem.GetFloatAttribute ("x");
		vertices [i].y = vertexElem.GetFloatAttribute ("y");
		vertices [i].z = vertexElem.GetFloatAttribute ("z");
		vertices [i].nx = vertexElem.GetFloatAttribute ("nx");
		vertices [i].ny = vertexElem.GetFloatAttribute ("ny");
		vertices [i].nz = vertexElem.GetFloatAttribute ("nz");
		vertices [i].tu = vertexElem.GetFloatAttribute ("tu");
		vertices [i].tv = vertexElem.GetFloatAttribute ("tv");
	}
	for (unsigned i=0; i<numTrigons; i++)
	{
		ceXmlElement trigElem = indicesElem.GetChild (i, "t");
		indices [i*3+0] = trigElem.GetIntAttribute ("v0");
		indices [i*3+1] = trigElem.GetIntAttribute ("v1");
		indices [i*3+2] = trigElem.GetIntAttribute ("v2");
	}


	LPDIRECT3DVERTEXDECLARATION9 d3dvd;
	LPDIRECT3DVERTEXBUFFER9 d3dvb;
	LPDIRECT3DINDEXBUFFER9 d3dib;
	void* data;

	D3DVERTEXELEMENT9 elements [] = {
		{ 0,   0, D3DDECLTYPE_FLOAT3,		D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION,		0 },
		{ 0,  12, D3DDECLTYPE_FLOAT3,	  D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,			0 },
		{ 0,  24, D3DDECLTYPE_FLOAT2,	  D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD,   0 },
		D3DDECL_END ()
	};

	if (FAILED(device->CreateVertexDeclaration (elements, &d3dvd))) return false;
	if (FAILED(device->CreateVertexBuffer (sizeof (Vertex) * numVertices, 0, 0, D3DPOOL_DEFAULT, &d3dvb, 0))) return false;
	if (FAILED(device->CreateIndexBuffer (sizeof (unsigned short) * numIndices, 0, D3DFMT_INDEX16, D3DPOOL_DEFAULT, &d3dib, 0))) return false;

	if (SUCCEEDED(d3dvb->Lock (0, sizeof (Vertex) * numVertices, &data, 0)))
	{
		memcpy (data, vertices, sizeof (Vertex) * numVertices);
		d3dvb->Unlock();
	}
	if (SUCCEEDED(d3dib->Lock (0, sizeof (unsigned short) * numIndices, &data, 0)))
	{
		memcpy (data, indices, sizeof (unsigned short) * numIndices);
		d3dib->Unlock ();
	}

	ceRenderMesh* rmesh = new ceRenderMesh ();
	rmesh->SetVertices(d3dvb, numIndices);
	rmesh->SetIndices (d3dib, numTrigons);
	rmesh->SetVertexDeclaration (d3dvd, sizeof (Vertex));
	rmesh->GetBoundingBox ().Clear ();
	for (unsigned i=0; i<numVertices; i++)
	{
		rmesh->GetBoundingBox ().AddVector3 (vertices[i].x, vertices[i].y, vertices[i].z);
	}
	rmesh->GetBoundingBox ().Update ();

	delete [] vertices;
	delete [] indices;

  return rmesh;
}
